home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS Toolkit
/
BBS Toolkit.iso
/
doors_2
/
o_ren171.zip
/
O_RENUM.C
next >
Wrap
Text File
|
1991-08-05
|
41KB
|
1,455 lines
/* #define OS2 1 */
/**************************************************************************
I hate to do this, but here goes:
The source code for O_RENUM is provided for your use and examination.
Because of a recent malicious "hack" of the source code, you are ASKED NOT
to make the source available for DownLoad or FileRequest without my
permission. This is to protect the FIDOnet community more than it is
to protect the source code itself.
If you make any changes to the program that you would like to see
incorporated into MY next release, please SEND CODE <tm, Wynn Wagner III>
or enough information to understand what needs to be done. My FIDOnet
node number is 1:133/302. My EGGnet address is 99:9000/6.
Steve Antonoff
Atlanta, GA
August 8, 1990
***********************************************************************
O_RENUM.C Does message renumbering for Opus 1.1x+ in "straight" C.
No fancy low-level calls, will probably be slower than Bob Hartman's
but will work on anything.
Fully released to the Opus community. Have fun, make it faster/better
just keep it free!
Doug Boone 119/5
P.O. Box 5108
Chico, CA 959528
Thanks to Bob Hartman for providing code. Although I didn't use any of
his code, being able to understand the logic and procedures he used
were extremely important.
---------------------------------------------------------------------
Pre-1.10 1/12/90 Steve Antonoff
Compiled with COMPACT model of TurboC
Added ECHO.CTL searching and command line
argument for SYSTEM directory
1.10.ix.A 1/22/90 Steve Antonoff
Applied Bob Davis' fix for 1.MSG 1/22/90 Steve Antonoff
added "adopted" and "thanks" lines
Added OPUS version number and COMPDATE
1.10.ix.C 1/31/90 Steve Antonoff:
Added additional checks to prevent killing of 1.msg in echo areas
Added -T (threshhold) option
Changed fgetc/fputc to fread/fwrite for LASTREAD file
1.10.ix.D 02/24/90 Steve Antonoff
Fixed error that occured if last message read was being deleted
Changed program name from RENUM to O_RENUM
1.10.ix.E 02/25/90 Steve Antonoff
Fixed renumbering to include last message (bug introduced in .ix.D)
1.10.ix.F 02/26/90 Steve Antonoff
Fixed processing for -N option to not require -R at the same time
1.10.ix.G 03/06/90 Steve Antonoff
Fixed processing for 1.MSG to update high water mark properly
1.10 3/13/90 Steve Antonoff
Reversed order for test on high water mark
Official release version for OPUS 1.10
1.10A 3/17/90 Steve Antonoff
Fixed update of LASTREAD to reflect correct value (was off by 1)
1.10B 3/19/90 Steve Antonoff
Added -W (write) and -A (automatic) options to write and read
renum parameters from RENUM.DAT in the OPUS SYSTEM path.
1.10C 3/19/90 Steve Antonoff
Fixed -N to count 1.MSG in the count of messages kept below #
1.10D 3/25/90 Steve Antonoff
Suppressed RENUMBER and RELINK if -R is not specified
1.10E 4/01/90 Steve Antonoff
-W only writes the parameters - doesn't do any renumbering
set exit() errorlevels to indicate error condition to DOS:
0 Successful or no renumber based on threshhold
1 Neither area number nor name given
2 Insufficient memory for message data
3 Error getting system info from SYSTEM.DAT
4 Write of RENUM parameters requested - no other processing performed
5 Can't find message path
6 Insufficient memory for user file data
7 Message number exceeds requeste max
8 Help (no arguments given)
1.10F 6/23/90 Steve Antonoff
"Neatened" up the status displays while running.
Added a display of the number of messages found.
Improved intelligence of command line parser to accept directory and
file names with or without an intervening space.
1.13 6/30/90 Steve Antonoff
Converted to "sparse" array manipulation, using qsort() to sort
message array. Thus, if an area has messages 1, 1000-1010, only 13
message slots will be used rather than 1011. Slot 0 is not used
ever.
Changed message number displays from %4d to %5d, allowing a full
32K-1 to be displayed properly.
1.13A 7/8/90 Steve Antonoff
Fixed bug in -M argument processing: 'M' was not listed in the switch
statement as a single parameter argument
1.13B 7/28/90 Steve Antonoff
Added -V (verbose) option and changed display of message numbers and
user names to default to off (quiet mode)
Added -Q (quiet) option to surpress normal status messages
Added -C (change directory) for future version
1.13C 7/31/90 Steve Antonoff
Changed test to allow -N option to allow -N=0,x
Fixed logic to use msg_count rather than max_msg in various places;
Use in_number and out_number rather than the index in various places
to accommodate sparse matrix
1.13D 8/9/90 Steve Antonoff
Changed calls to fix_lastread and fix_user back to use new_max_msg,
which is correctly returned from relink. 1.13C incorrectly used
msg_count for these two routines, resulting in message counts for
lastread and user renumber. The lastread/user lastread counters
are only adjusted if new_max_msg is not equal to max_msg, indicating
that some adjustment might be necessary.
1.13E 8/31/90 Steve Antonoff
Added check for 4 byte LASTREAD file as used by MSGED. Both pointers
are adjusted if a 4 byte file is found.
1.13F 9/8/90 Steve Antonoff
1) Extended 1.13E changes to include variable length LASTREAD files
to accommodate other message handlers. The LASTREAD file is treated
as a list of int, each int adjusted independently.
2) Corrected error in handling of QUIET mode: if QUIET was engaged,
message renumbering might have been disabled in certain circumstances.
1.71 8/5/91 Doug Boone.
Update for Opus 1.7x
***************************************************************************/
#include <stdio.h>
#include <dos.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#include <stdlib.h>
#ifdef __TURBOC__
#include <alloc.h>
#include <dir.h>
#else
#include <malloc.h>
#endif
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#ifdef OS2
#define INCL_GPI
#define INCL_BASE
#define INCL_DOS
#include <os2.h>
#endif
/*#include "otoolkit.h"*/
/*#include "compdate.h" */
#include "newuser.h"
#include "system.h"
#define VERSION "1.71"
#define MAX_USERS 24 /* Maximum # of users to update at once */
#define MAX_PATH 80 /* Maximum file path */
#define MAX_NAME 33 /* Maximum echo name */
#ifndef FALSE
#define FALSE 0
#define TRUE !FALSE
#endif
/*------------------------------------------------------------------------*/
/* Set of values to use with "flags" to tell renum what to do */
/*------------------------------------------------------------------------*/
#define KILL_DAYS 0x0001
#define KILL_NUMBER 0x0002
#define KILL_RCVD 0x0004
#define KILL_SENT 0x0008
#define RENUMBER 0x0010
#define RELINK_MSG 0x0020
#define IS_ECHO 0x1000
/*------------------------------------------------------------------------*/
/* Message status flags */
/*------------------------------------------------------------------------*/
#define ZAP 0x0001
#define EXISTS 0x0002
#define NOT_HERE 0x0000
/*------------------------------------------------------------------------*/
/* Return values */
/*------------------------------------------------------------------------*/
/*#define ERROR -1 */
#define SUCCESS 1
/*------------------------------------------------------------------------*/
/* Used to generate dates */
/*------------------------------------------------------------------------*/
#define YEAR_SHIFT 9
#define MONTH_SHIFT 5
#define DOS_EPOCH 80
#ifndef ERROR
#define ERROR (-1)
#endif
/*------------------------------------------------------------------------*/
/* The basic internal structure to keep track of messages */
/*------------------------------------------------------------------------*/
struct a_msg
{
int status; /* internal renum status for this message */
int in_number; /* what was the original message number */
int out_number; /* what is the output number going to be */
int how_old; /* date_received date stamp */
int uplink; /* "there is a reply....." */
int downlink; /* "this is a reply to ......" */
int attr; /* the message's attribute */
};
/*------------------------------------------------------------------------*/
/* Global Data */
/*------------------------------------------------------------------------*/
struct a_msg *msg;
int MAX_MSGS = 1024; /* default max message area size */
char msg_path[MAX_PATH]; /* the message area path */
char echo_name[MAX_NAME]; /* the echo area name */
/*int flags = RELINK_MSG;*/ /* RENUM flags so we know what to do */
char *msg_file_format = "%s%i.MSG"; /* Format for message file name */
int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int area = -1; /* What area number is being used */
char echo_ctl_name[MAX_PATH],opus_sys_path[MAX_PATH];
int verbose = FALSE;
int quiet = FALSE;
int change_dir = FALSE;
int Opus_120 = FALSE;
struct flag_struct /* RENUM flags so we know what to do */
{
unsigned threshhold:1;
unsigned kill_days:1;
unsigned kill_number:1;
unsigned kill_rcvd:1;
unsigned kill_sent:1;
unsigned renumber:1;
unsigned relink:1;
unsigned is_echo:1;
unsigned spare:8;
};
struct renum_param /* RENUM parameter structure */
{
struct flag_struct flags;
int days;
int keep_lo,keep_hi;
int min_delete;
}renum,renum_from_file;
/*------------------------------------------------------------------------*/
/* Procedure definitions */
/*------------------------------------------------------------------------*/
void fix_lastread(int);
void fix_users(int,int);
int relink(int);
void delete_msgs(int);
int kill_count(int);
int message_count(int);
int get_sys_info(int,char *);
int get_msg_info(int *);
int msg_age_as_of(int);
void no_parms(int,int);
int scan_echo_ctl(char *, char *, char *);
int proc_args(int, char **);
void show_params(int);
int read_param_data(int,char *);
int write_param_data(int,char *);
#ifdef __TURBOC__
int msg_cmp(const void *,const void *);
#else
int msg_cmp(struct a_msg *,struct a_msg *);
#endif
void xprintf(const char *);
/*--------------------------------------------------------------------------*/
extern long get_msgpos(int,char *);
extern char * pascal getstring(byte,int);
void fix_lread_dat(int);
/*--------------------------------------------------------------------------*/
void xprintf(const char *s)
{
if (!quiet)
printf("%s",s);
}
#ifdef __TURBOC__
int msg_cmp(const void *msg1,const void *msg2)
{
struct a_msg *m1,*m2;
m1 = (struct a_msg *)msg1;
m2 = (struct a_msg *)msg2;
return (m1->in_number - m2->in_number);
}
#else
int msg_cmp(struct a_msg *msg1,struct a_msg *msg2)
{
return (msg1->in_number - msg2->in_number);
}
#endif
int add_slash(char *path)
{
char last_char;
last_char = path[strlen(path)-1];
if (last_char != '\\' && last_char != ':')
strcat(path,"\\");
return last_char;
}
int main(int argc,char *argv[])
{
int i = 1;
int j;
int k;
#ifdef OLDVERSION
int days; /* Number of days for deleting */
int keep_lo;
int keep_hi;
int min_delete=-1;
#endif
int killed_count=0;
int write_data=0; /* 0 = no action, 1 = write data, 2 = read data*/
int older; /* Date stamp for older messages */
int max_msg; /* Highest message number found */
int new_max_msg; /* Highest message after renumbering */
int msg_count; /* Number of messages found */
no_parms(argc-1,0); /* give instructions or credit */
msg_path[0] = 0; /* blast out msg_path */
echo_name[0] = 0;
echo_ctl_name[0] = 0;
opus_sys_path[0] = 0;
renum.min_delete = 0;
renum.flags.threshhold = FALSE;
renum.flags.kill_days = FALSE;
renum.flags.kill_number = FALSE;
renum.flags.kill_rcvd = FALSE;
renum.flags.kill_sent = FALSE;
renum.flags.renumber = FALSE;
renum.flags.relink = TRUE;
renum.flags.is_echo = FALSE;
write_data = proc_args(argc,argv);
if (!(msg_path[0]) && (area==-1))
{
printf("Neither message area directory nor area number given\n");
exit(1);
}
if ( NULL ==
(msg = (struct a_msg *) calloc(sizeof(struct a_msg),MAX_MSGS) ) )
{
printf("Unable to allocate space for %d messages\n",MAX_MSGS);
exit(2);
}
if (echo_ctl_name[0])
{
add_slash(echo_ctl_name);
strcat(echo_ctl_name,"ECHO.CTL");
}
if (opus_sys_path[0])
add_slash(opus_sys_path);
else
write_data = 0; /* can't read or write without OPUS system path */
if (msg_path[0])
{
strcpy(echo_name,msg_path);
add_slash(msg_path);
area = scan_echo_ctl(msg_path,echo_name,echo_ctl_name);
}
if (!(msg_path[0])) /* If the message path is no good..... */
{
if (ERROR == get_sys_info(area,opus_sys_path) )
exit(3);
}
if ((write_data & 2) && area > -1)
{
read_param_data(area,opus_sys_path);
proc_args(argc,argv);
}
show_params(write_data);
if ((write_data & 1) && area > -1)
{
write_param_data(area,opus_sys_path);
printf("Data written - O_RENUM terminating\n");
exit(4);
}
if (renum.flags.is_echo)
xprintf("Treating area as ECHOMAIL....\n");
i = strlen(msg_path) - 1;
if (msg_path[i] == '\\')
msg_path[i] = '\0';
if (access(msg_path,0))
{
printf("Can't find path %s\n\n",msg_path);
exit(5);
}
strcat(msg_path,"\\");
printf("Checking messages in %s\n",msg_path);
max_msg = get_msg_info(&msg_count);
if (!quiet)
{
printf("Max message number found: %d\n",max_msg);
printf("Number of messages found: %d\n",msg_count-1);
printf("Sorting message array...\n");
}
qsort(msg,(size_t)msg_count,sizeof (struct a_msg),msg_cmp);
if (renum.flags.kill_sent)
{
xprintf("Marking messages that have been sent........\n");
for (i = 0; i<= msg_count; i++)
if (msg[i].attr & MSGSENT)
msg[i].status = ZAP;
}
if (renum.flags.kill_rcvd)
{
xprintf("Marking messages that have been received....\n");
for (i = 0; i<= msg_count; i++)
if (msg[i].attr & MSGREAD)
msg[i].status = ZAP;
}
if (renum.flags.kill_days)
{
xprintf("Marking old messages....\n");
older = msg_age_as_of(renum.days);
for (i = 1; i<= msg_count; i++)
if (msg[i].how_old < older)
msg[i].status = ZAP;
}
if (renum.flags.kill_number)
{
if (!quiet)
printf(
"Marking messages after #%i and before the highest %i messages.....\n",
renum.keep_lo,renum.keep_hi);
}
else
{
renum.keep_hi = msg_count;
renum.keep_lo = 1;
}
if (renum.flags.kill_number)
{
j = renum.keep_hi;
i = msg_count;
while (j > 0 && i > renum.keep_lo)
{
if (EXISTS == msg[i].status)
j--;
i--;
}
if (renum.flags.is_echo) /* don't kill 1.msg for echos */
{
k = 2;
j = 1; /* but remember that we haven't! */
}
else
{
k = 1;
j = 0;
}
while (j < renum.keep_lo && k <= i)
{
if (EXISTS == msg[k].status)
j++;
k++;
}
for (j = k;j <= i;j++)
msg[j].status = ZAP;
}
killed_count = kill_count(msg_count);
if (renum.flags.threshhold && (killed_count < renum.min_delete) )
{
printf("Fewer than %i messages to delete (%i) - terminating\n",
renum.min_delete,killed_count);
exit(0);
}
if (!quiet)
printf("Killing %i messages....\n",killed_count);
delete_msgs(msg_count);
if (renum.flags.renumber)
{
new_max_msg = relink(msg_count);
if (new_max_msg != max_msg)
{
fix_lastread(new_max_msg);
if (area != -1) {
if (Opus_120) {
fix_lread_dat(new_max_msg);
}
/* else Uncomment this line for newer version*/
/* if (area < 256)
fix_users(new_max_msg,area); */
}
}
}
exit(0);
return 0;
}
/*------------------------------------------------------------------------*/
/* Fix up LASTREAD in this area */
/*------------------------------------------------------------------------*/
void fix_lastread(int max)
{
char full[MAX_PATH];
FILE *infp;
int last_msg;
int i;
int hit;
long last_leng,last_cnt;
sprintf(full,"%sLASTREAD",msg_path);
if ((infp = fopen(full,"r+b")) == NULL)
return;
fseek(infp,0L,SEEK_END);
last_leng = ftell(infp);
fseek(infp,0L,SEEK_SET);
if (verbose || !quiet)
printf("Updating %s:\n",full);
for (last_cnt = 0 ; last_cnt < last_leng ; last_cnt += 2)
{
hit = FALSE;
fseek(infp,last_cnt,SEEK_SET);
fread(&last_msg,2,1,infp);
if (last_msg > 0)
{
if (verbose || !quiet)
printf(" %d ->",full,last_msg);
for (i = max; i >= 1 && !hit ; i--)
{
if (msg[i].in_number <= last_msg)
{
last_msg = msg[i].out_number;
hit = TRUE;
}
}
if (!hit)
last_msg = 0;
fseek(infp,last_cnt,SEEK_SET);
fwrite(&last_msg,2,1,infp);
if (verbose || !quiet)
{
printf("%d\n",last_msg);
}
}
}
fclose(infp);
return;
}
/*------------------------------------------------------------------------*/
/* Fix up user records, resetting message areas as needed */
/*------------------------------------------------------------------------*/
void fix_users(int high,int area)
{
struct _usr *auser;
int i;
int j;
int k;
int hit=FALSE;
int user_no = 0;
FILE *infp;
if ( (auser =
(struct _usr *)calloc(MAX_USERS, sizeof (struct _usr) ) ) ==
NULL)
{
printf("Unable to allocate memory for user file buffer\n");
exit(6);
}
if ((infp = fopen("USER.DAT","r+b")) == NULL)
{
printf("\nCouldn't find USER.DAT!!\n");
return;
}
xprintf("Updating USER records..........\n");
while ((k = fread(auser,sizeof(struct _usr),MAX_USERS,infp)) > 0)
{
for (i = 0; i < k; i++)
{
user_no++;
if (auser[i].lastmsg[area] > 0)
{
hit = FALSE;
for (j = high; j >= 1 && !hit; j--)
{
if (msg[j].in_number <= auser[i].lastmsg[area])
{
if (verbose && !quiet)
printf("\r%5d -> %5d: (%d) %-40.40s",
auser[i].lastmsg[area],msg[j].out_number,
user_no,auser[i].name);
auser[i].lastmsg[area] = msg[j].out_number;
hit = TRUE;
}
}
if (!hit)
auser[i].lastmsg[area] = 1;
}
}
fseek(infp,-((long) (k * sizeof(struct _usr))),SEEK_CUR);
fwrite(auser,sizeof(struct _usr),k,infp);
};
fclose(infp);
free(auser);
printf("\n");
return;
}
/*------------------------------------------------------------------------*/
/* Relink the replies in the message headers */
/*------------------------------------------------------------------------*/
int relink(int high)
{
int i,hit;
int j = 1;
int low = 1;
char new[MAX_PATH];
char old[MAX_PATH];
FILE *infp;
struct _msg amsg;
if (!quiet)
printf("Renumbering %sMessages........\n",
(renum.flags.relink) ?"& Relinking ":"");
if (renum.flags.is_echo)
{
low = 2;
j = 2;
}
/*------------------------------------------------------------------------*/
/* This is where renumbering really takes place, finding the messages */
/* that are still marked as EXISTS and crunching them down. */
/*------------------------------------------------------------------------*/
for (i = low; i <= high; i++)
{
if (EXISTS == msg[i].status)
{
msg[j].status = msg[i].status;
msg[j].in_number = msg[i].in_number;
msg[j].out_number = j;
msg[j].how_old = msg[i].how_old;
msg[j].uplink = msg[i].uplink;
msg[j].downlink = msg[i].downlink;
msg[j].attr = msg[i].attr;
j++;
}
}
/*------------------------------------------------------------------------*/
/* Now we've packed down the msg array and found the new highest message */
/* so begin the process of re-linking the replies */
/*------------------------------------------------------------------------*/
high = j;
if (high)
high--;
if (renum.flags.is_echo)
{
if (msg[1].status > 0)
msg[1].status = EXISTS;
if (msg[1].downlink > 0) /* Handle 1.MSG for echoes */
{
hit = FALSE;
for (j = high; j > 0 && !hit ;j--) /* High Water Mark */
{
if (msg[j].in_number <= msg[1].downlink)
{
msg[1].downlink = msg[j].out_number;
j = high;
hit = TRUE;
}
}
}
if (msg[1].uplink > 0)
{
hit = FALSE;
for (j = high; j > 0 && !hit; j--)
{
if (msg[j].in_number == msg[1].uplink)
{
msg[1].uplink = msg[j].out_number;
j = high;
hit = TRUE;
}
}
}
sprintf(new,"%s1.MSG",msg_path);
infp = fopen(new,"r+b");
fread(&amsg,sizeof(struct _msg),1,infp);
amsg.reply = msg[1].downlink;
amsg.up = msg[1].uplink;
fseek(infp,0L,SEEK_SET);
fwrite(&amsg,sizeof(struct _msg),1,infp);
fclose(infp);
} /* End of special handling for message #1 */
for (i = low; i <= high; i++)
{
if (msg[i].downlink > 0)
{
hit = FALSE;
for (j = low; j < i && !hit; j++)
{
if (msg[j].in_number == msg[i].downlink)
{
msg[i].downlink = j;
hit = TRUE;
}
}
}
if (msg[i].uplink > 0)
{
hit = FALSE;
for (j = i; j <= high && !hit; j++)
{
if (msg[j].in_number == msg[i].uplink)
{
msg[i].uplink = j;
hit = TRUE;
}
}
}
}
/*------------------------------------------------------------------------*/
/* Rename the messages */
/*------------------------------------------------------------------------*/
for (i = low; i <= high; i++)
{
if (msg[i].in_number != i)
{
sprintf(new,msg_file_format,msg_path,msg[i].out_number);
sprintf(old,msg_file_format,msg_path,msg[i].in_number);
if (verbose && !quiet)
printf("\r%5d -> %5d",msg[i].in_number,msg[i].out_number);
if (rename(old,new) != 0)
{
unlink(new);
rename(old,new);
}
if ( (msg[i].uplink || msg[i].downlink) && (renum.flags.relink) )
{
infp = fopen(new,"r+b");
fread(&amsg,sizeof(struct _msg),1,infp);
amsg.reply = msg[i].downlink;
amsg.up = msg[i].uplink;
fseek(infp,0L,SEEK_SET);
fwrite(&amsg,sizeof(struct _msg),1,infp);
fclose(infp);
}
}
}
if (verbose && !quiet)
printf("\n");
return(high); /* Return the new max_msg */
}
/*------------------------------------------------------------------------*/
/* Delete all the messages who have a status of ZAP */
/*------------------------------------------------------------------------*/
void delete_msgs(int high)
{
char full[MAX_PATH];
int i;
int j = 1;
if (renum.flags.is_echo)
j = 2;
for (i = j;i <= high;i++)
{
if (ZAP == msg[i].status)
{
if (verbose && !quiet)
printf("Kill %5d\r",msg[i].in_number);
sprintf(full,msg_file_format,msg_path,msg[i].in_number);
unlink(full);
}
}
if (verbose && !quiet)
printf("\n");
return;
}
/*------------------------------------------------------------------------*/
/* Read the SYSTEM*.DAT path, only works with Opus 1.10! */
/*------------------------------------------------------------------------*/
int get_sys_info(int area,char *opus_sys_path)
{
struct _sys one_sys;
FILE *handle;
char sys_path[MAX_PATH];
struct _msgsys asys;
long f_pos;
int fh;
char *junk;
if (Opus_120) {
if ((f_pos = get_msgpos(area,opus_sys_path)) < 0L)
return(ERROR);
sprintf(sys_path,"%sSYSMSG.DAT",opus_sys_path);
if ((fh = open(sys_path,O_RDONLY|O_BINARY)) < 0) {
printf("\nFailed to open %s\n",sys_path);
return(ERROR);
}
lseek(fh,f_pos,SEEK_SET);
read(fh,(char*)&asys,sizeof(struct _msgsys));
junk = getstring(asys.Path_Len,fh);
strcpy(msg_path,junk);
free(junk);
close(fh);
if (asys.Attrib & ECHOMAIL)
renum.flags.is_echo = TRUE;
return(SUCCESS);
}
/*--------------------------------------------------------------------------*/
sprintf(sys_path,"%sSYSTEM%02X.DAT",opus_sys_path,area);
if ((handle = fopen(sys_path,"rb")) == NULL)
{
printf("Couldn't open %s!!\n",sys_path);
return(ERROR);
}
if ((fread(&one_sys,sizeof(struct _sys),1,handle)) < 0)
{
printf("Error reading %s!!\n",sys_path);
fclose(handle);
return(ERROR);
}
strcpy(msg_path,(char *)one_sys.msgpath);
fclose(handle);
if (one_sys.attrib & ECHOMAIL)
renum.flags.is_echo = TRUE;
return(SUCCESS);
}
/*------------------------------------------------------------------------*/
/* Read the message headers and load up the msg[] array */
/*------------------------------------------------------------------------*/
int get_msg_info(int *count)
{
struct _msg amsg;
char fullpath[MAX_PATH];
FILE *handle;
#ifdef __TURBOC__
struct ffblk ffblk;
#elif OS2
HDIR hdir;
USHORT usSearch;
FILEFINDBUF findbuf;
#else
struct find_t ffblk;
#endif
int done;
int i;
int high_msg = 0;
*count = 1;
sprintf(fullpath,"%s*.MSG",msg_path);
#ifdef __TURBOC__
done = findfirst(fullpath,&ffblk,0);
#elif OS2
DosFindFirst(fullpath,&hdir,0x0017,&findbuf,sizeof(findbuf),&usSearch,0L);
if (usSearch)
done = 0;
else
done = 1;
printf("\nPath: %s Result: %s %x %x",fullpath,findbuf.achName,usSearch,done);
#else
done = _dos_findfirst(fullpath,_A_NORMAL,&ffblk);
#endif
printf("Checking:\n");
while (!done) {
#ifdef __TURBOC__
i = atoi(ffblk.ff_name);
#elif OS2
i = atoi(findbuf.achName);
printf("\nFile: %s Done = %x %x",
findbuf.achName,done,usSearch);
#else
i = atoi(ffblk.name);
#endif
if (i > MAX_MSGS)
{
printf("Message number %d exceeds max limit\n",i);
exit(7);
}
sprintf(fullpath,msg_file_format,msg_path,i);
if ((handle = fopen(fullpath,"rb")) == NULL)
msg[i].status = NOT_HERE;
else
{
if ((fread(&amsg,sizeof(struct _msg),1,handle)) < 0)
msg[i].status = ZAP; /* this must be a bogus message, no header */
else
{
if (verbose && !quiet)
printf("%5d\r",i);
msg[*count].status = EXISTS;
msg[*count].in_number = i;
msg[*count].uplink = amsg.up;
msg[*count].downlink = amsg.reply;
msg[*count].attr = amsg.attr;
msg[*count].how_old = amsg.date_arrived.date;
}
if (high_msg < i)
high_msg = i;
fclose(handle);
}
(*count)++;
#ifdef __TURBOC__
done = findnext(&ffblk);
#elif OS2
done = DosFindNext(hdir,&findbuf,sizeof(findbuf),&usSearch);
if (usSearch)
done = 0;
else
done = 1;
#else
done = _dos_findnext(&ffblk);
#endif
};
if (verbose && !quiet)
printf("\n");
return(high_msg);
}
/*------------------------------------------------------------------------*/
/* Work out what the date stamp would have been on the date (how_old) ago */
/*------------------------------------------------------------------------*/
int msg_age_as_of(int kill_date)
{
int day;
int month;
int year;
int check;
#ifdef OS2
struct _DATETIME date;
DosGetDateTime(&date);
month = date.month;
day = date.day;
year = date.year;
#else
union REGS inregs,outregs;
inregs.h.ah = 0x2a;
intdos(&inregs,&outregs);
year = outregs.x.cx;
month = outregs.h.dh;
day = outregs.h.dl;
#endif
while (kill_date > 0)
{
if (day > kill_date)
{
day -= kill_date;
kill_date = 0;
}
else
{
months[1] = (year % 4 ? 28 : 29); /* Leap years through 2099 */
if (month == 1) /* move back to previous year */
{
if (kill_date >= 31)
kill_date -= 31;
else
{
day = 31 + day - kill_date;
kill_date = 0;
}
year--;
month = 12;
}
else
{
if (kill_date >= months[month-2])
kill_date -= months[month-2];
else
{
day = months[month-2] + day - kill_date;
kill_date = 0;
}
month--;
}
}
}
/*------------------------------------------------------------------------*/
if (!quiet)
printf("Kill older than: %02d-%02d-%4d\n",month,day,year);
/*------------------------------------------------------------------------*/
year = (year % 100);
year -= DOS_EPOCH;
check = year << YEAR_SHIFT;
check += month << MONTH_SHIFT;
check += day;
return(check);
}
/*------------------------------------------------------------------------*/
/* Your basic help and exit messages */
/*------------------------------------------------------------------------*/
void no_parms(int argc,int arg_char)
{
printf("\n\n"
"O_RENUM %s %s - adopted by Steve Antonoff, 133/302\n"
"Thanks to Bob Hartman, Doug Boone and Bob Davis.\n",
VERSION,__DATE__);
if (argc > 0)
return;
if (argc < 0)
printf("\nError detected in command option: %c\n",arg_char);
printf(
"\n"
"Use as O_RENUM [-K] [-N #1 #2] [-D ##] [-S] [-M #] [-F] [-E path]\n"
" [-O path] [-T #] [-Q] [-V] [-R] [#|path|conf]\n"
"\n"
"-2 .............. Opus 1.7x!\n"
"-K .............. Kill received messages\n"
"-S .............. Delete messages that have already been sent\n"
"-N #1 #2 ........ Keep the first #1 messages and the last #2 messages\n"
"-D ## ........... Kill message more than ## days old\n"
"-M # ............ Maximum number of messages to handle (100-4500)\n"
"-F .............. Fast renum (don't relink message chains)\n"
"-E path ......... Path (disk:\\dir) to ECHO.CTL\n"
"-O path ......... Path (disk:\\dir) to OPUS SYSTEM??.DAT files\n"
"-T # ............ Threshhold (kill only if more than # msgs to kill)\n"
"-Q .............. Quiet mode (few displays)\n"
"-V .............. Verbose mode (message count & user names displayed)\n"
"-R .............. Renumber the messages\n"
"-W .............. Write parameters to RENUM.DAT and terminate\n"
"-A .............. Automatic renum (use data in RENUM.DAT\n"
"#/path/conf ..... Area number, path or conference name (tag) for messages\n"
"-W and -A require an area number, either from the command line or from\n"
"ECHO.CTL; both require an OPUS SYSTEM PATH (-o)\n"
"\n"
"Commands and parameters may be separated by spaces or they can be run\n"
"together, or they can be separated by \"=\" and the -N option can use a\n"
"comma to separte the two numbers.\n");
exit(8);
}
int scan_echo_ctl(char *msg_path,char *area_name,char *echo_ctl_path)
{
FILE *ctl;
int areanum;
char echo_path[MAX_PATH];
char echo_name[MAX_NAME];
char buffer[256];
if (!quiet)
printf("Scanning %s for echo area directory %s...\n",
echo_ctl_path,msg_path);
if ( ( ctl = fopen(echo_ctl_path,"rt") ) == NULL )
{
printf("%s not found.....\n",echo_ctl_path);
return -1;
}
while (!feof(ctl))
{
if (fgets(buffer,255,ctl))
{
sscanf(buffer,"%d %s %s",&areanum,echo_path,echo_name);
if ( !stricmp(echo_path,msg_path ) ||
!stricmp(echo_name,area_name) )
{
if (!quiet)
printf("Found: area #%d.....\n",areanum);
fclose(ctl);
msg_path[0] = 0;
return areanum;
}
}
}
printf("%s (%s) not found.....\n",msg_path,area_name);
return -1;
}
int kill_count(int msg_count)
{
int i,kill=0;
xprintf("Counting messages to be killed....\n");
if ( (renum.flags.is_echo) && msg[1].status == ZAP)
msg[1].status = EXISTS;
for (i=1 ; i <= msg_count ; i++)
if (msg[i].status == ZAP)
kill++;
return kill;
}
/**************************************************************************/
int proc_args(int argc, char *argv[])
{
int arg=1,write_data=0;
char *arg_s,*arg_data1,*arg_data2;
static int first=TRUE;
if (first)
{
printf("Processing command line arguments....\n");
}
while (arg<argc)
{
strupr(argv[arg]);
arg_s = argv[arg];
if (*arg_s == '-' || *arg_s == '/')
{
++arg_s;
arg_data1 = arg_s + 1;
if (*arg_data1 == '=')
arg_data1++;
arg_data2 = arg_data1;
while (*arg_data2 && *arg_data2 != ',')
arg_data2++;
if (*arg_data2 == ',' || *arg_data2 == '=')
arg_data2++;
switch (*arg_s) /* group options:
no parameters,
one parameter,
two parameters */
{
case 'K': /* no parameters */
case 'S':
case 'F':
case 'R':
case 'W':
case 'A':
case 'V':
case 'Q':
case 'C':
break;
case 'D': /* one parameter */
case 'T':
case 'E':
case 'O':
case 'M':
case 'N': /* two parameters */
if (!(*arg_data1) ) /* no parameters within arg */
{
arg++;
arg_data1 = argv[arg];
arg_data2 = arg_data1;
while (*arg_data2 && *arg_data2 != ',')
arg_data2++;
if (*arg_data2 == ',' || *arg_data2 == '=')
arg_data2++;
}
if (*arg_s == 'N') /* only two parameter option */
{
if (!(*arg_data2) ) /* no second parameter */
{
arg++;
arg_data2 = argv[arg];
}
}
break;
}
switch(*arg_s)
{
case '2':
Opus_120 = TRUE;
break;
case 'V':
verbose = TRUE;
break;
case 'Q':
quiet = TRUE;
break;
case 'C':
change_dir = TRUE;
break;
case 'N':
renum.keep_lo = atoi(arg_data1);
renum.keep_hi = atoi(arg_data2);
renum.flags.kill_number = TRUE;
if (renum.keep_hi <= 0 || renum.keep_lo < 0)
no_parms(-1,*arg_s);
break;
case 'R':
renum.flags.renumber = TRUE;
break;
case 'D':
renum.days = atoi(arg_data1);
renum.flags.kill_days = TRUE;
if (renum.days <= 0)
no_parms(-1,*arg_s);
break;
case 'K':
renum.flags.kill_rcvd = TRUE;
break;
case 'S':
renum.flags.kill_sent = TRUE;
break;
case 'E':
if (first)
{
if (!(*arg_data1))
no_parms(-1,*arg_s);
strcpy(echo_ctl_name,arg_data1);
}
break;
case 'O':
if (first)
{
if (!(*arg_data1))
no_parms(-1,*arg_s);
strcpy(opus_sys_path,arg_data1);
}
break;
case 'M':
MAX_MSGS = atoi(arg_data1);
if (MAX_MSGS == 0)
no_parms(-1,*arg_s);
if (MAX_MSGS < 100)
MAX_MSGS = 100;
if (MAX_MSGS > 4500)
MAX_MSGS = 4500;
break;
case 'T':
renum.min_delete = atoi(arg_data1);
if (renum.min_delete <= 0)
no_parms(-1,*arg_s);
renum.flags.threshhold = TRUE;
break;
case 'F':
renum.flags.relink = FALSE;
break;
case 'W':
write_data += 1;
break;
case 'A':
write_data += 2;
break;
}
}
else
{
if (first)
{
if (isdigit(*argv[arg]) > 0) /* is this an area number? */
area = atoi(argv[arg]);
else
strcpy(msg_path,argv[arg]); /* must be just a path */
}
}
arg++;
}
first = FALSE;
return (write_data);
}
/**************************************************************************/
void show_params(int write_data)
{
char *on="ON",*off="OFF";
if (quiet)
return;
printf("\nWriting parameters: %s",write_data==1?on:off);
printf("\nReading parameters: %s",write_data==2?on:off);
printf("\nThreshhold: %s",renum.flags.threshhold?on:off);
if (renum.flags.threshhold)
printf(" %d messages minimum",renum.min_delete);
printf("\nDelete by days: %s",renum.flags.kill_days?on:off);
if (renum.flags.kill_days)
printf(" %d days old or older",renum.days);
printf("\nKill by Msg Number: %s",renum.flags.kill_number?on:off);
if (renum.flags.kill_number)
printf(" Leave first %d and last %d messages",
renum.keep_lo,renum.keep_hi);
printf("\nRelinking: %s",renum.flags.relink?on:off);
printf("\nRenumbering: %s",renum.flags.renumber?on:off);
printf("\nKill Sent: %s",renum.flags.kill_sent?on:off);
printf("\nKill Rcvd: %s",renum.flags.kill_rcvd?on:off);
if (*opus_sys_path)
printf("\nOPUS System Path: %s",opus_sys_path);
if (*echo_ctl_name)
printf("\nECHO.CTL Name: %s",echo_ctl_name);
printf("\nMessage path: %s",msg_path);
printf("\n");
}
int read_param_data(int area,char *opus_sys_path)
{
FILE *handle;
char sys_path[MAX_PATH];
sprintf(sys_path,"%sRENUM.DAT",opus_sys_path);
if ((handle = fopen(sys_path,"rb")) == NULL)
{
printf("Couldn't open %s!!\n",sys_path);
return(ERROR);
}
fseek(handle,(long)area * sizeof(struct renum_param),SEEK_SET);
if ((fread(&renum_from_file,sizeof(struct renum_param),1,handle)) < 0)
{
printf("Error reading %s!!\n",sys_path);
fclose(handle);
return(ERROR);
}
memcpy(&renum,&renum_from_file,sizeof(struct renum_param));
fclose(handle);
return(SUCCESS);
}
int write_param_data(int area,char *opus_sys_path)
{
FILE *handle;
char sys_path[MAX_PATH];
int area_no;
sprintf(sys_path,"%sRENUM.DAT",opus_sys_path);
if (access(sys_path,0))
{
if ( (handle = fopen(sys_path,"w+b") ) == NULL)
{
printf("Couldn't create %s!!\n",sys_path);
return (ERROR);
}
for (area_no = 0 ; area_no < 256 ; area_no++)
{
if ((fwrite(&renum,sizeof(struct renum_param),1,handle)) < 0)
{
printf("Error initializing %s!!\n",sys_path);
return(ERROR);
}
}
fclose(handle);
}
if ( ( handle = fopen(sys_path,"r+b") ) == NULL)
{
printf("Couldn't open %s!!\n",sys_path);
return(ERROR);
}
fseek(handle,(long)area * sizeof(struct renum_param),SEEK_SET);
if ((fwrite(&renum,sizeof(struct renum_param),1,handle)) < 0)
{
printf("Error writing %s!!\n",sys_path);
fclose(handle);
return(ERROR);
}
fclose(handle);
return(SUCCESS);
}
void fix_lread_dat(int high)
{
int infh;
int outfh;
int hit;
int j;
struct _lmr lreads;
char old_name[80];
char new_name[80];
strcpy(old_name,msg_path);
strcpy(new_name,msg_path);
strcat(old_name,"LREAD.OLD");
strcat(new_name,"LREAD.DAT");
if (!quiet)
printf("\nUpdating %s",old_name);
unlink(old_name);
rename(new_name,old_name);
infh = open(old_name,O_BINARY|O_RDONLY);
outfh = open(new_name,O_BINARY|O_WRONLY|O_CREAT,S_IWRITE|S_IREAD);
while ((read(infh,(char *)&lreads,sizeof(struct _lmr))) == sizeof(struct _lmr)) {
hit = 0;
for (j = high; j > 1 && hit != 3; j--) {
if (msg[j].in_number <= lreads.last_msg) {
lreads.last_msg = j;
hit |= 0x01;
} /* End of success handling */
if (msg[j].in_number <= lreads.high_msg) {
lreads.high_msg = j;
hit |= 0x02;
}
} /* End of for() loop */
if (!hit)
continue;
if (!(hit & 0x02))
lreads.high_msg = lreads.last_msg;
if (!(hit & 0x01))
lreads.last_msg = lreads.high_msg;
write(outfh,(char *)&lreads,sizeof(struct _lmr));
} /* End of while loop */
close(infh);
close(outfh);
unlink(old_name);
return;
}